﻿// Copyright 2009 Mike Geise
// 
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// 
//     http://www.apache.org/licenses/LICENSE-2.0
// 
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

namespace Falcon.Core.Services
{
	using System;
	using System.Web;
	using System.Web.Security;
	using Falcon.Core.Domain;
	using Falcon.Core.Domain.Repositories;
	using Falcon.Core.Domain.Services;
	using Falcon.Core.Domain.Values;
	using Falcon.Core.Email;
	using Falcon.Core.Extensions;
	using Falcon.Core.Helpers;

	public class FormsAuthenticationService : IAuthenticationService
	{
		public FormsAuthenticationService(
			IEmailService emailService, 
			IUserRepository userRepository)
		{
			this.EmailService = emailService;
			this.UserRepository = userRepository;
		}

		public IEmailService EmailService
		{
			get;
			private set;
		}

		public IUserRepository UserRepository
		{
			get; 
			private set;
		}

		public string ReturnUrl
		{
			get
			{
				 return FormsAuthentication.DefaultUrl;
			}
		}

		public string LoginUrl
		{
			get
			{
				return FormsAuthentication.LoginUrl;
			}
		}

		public void Login(UserAuthentication value)
		{
			value.Validate();

			var context = HttpContext.Current;

			if (context == null)
			{
				return;
			}

			var user = UserRepository.GetBy(new UserSpecification
			{
				EmailAddress = value.EmailAddress
			});

			user.LastLogOn = DateTime.Now;

			UserRepository.Update(user);

			// get auth cookie
			var auth = FormsAuthentication.GetAuthCookie(user.EmailAddress, value.Persistent);

			// decrypt auth cookie value
			var current = FormsAuthentication.Decrypt(auth.Value);

			// create new auth ticket
			var ticket = new FormsAuthenticationTicket(
				current.Version,
				current.Name,
				current.IssueDate,
				current.Expiration,
				current.IsPersistent, 
				string.Empty);

			// encrypt new auth ticket
			auth.Value = FormsAuthentication.Encrypt(ticket);

			// add auth cookie
			context.Response.Cookies.Add(auth);
		}

		public void Logout()
		{
			FormsAuthentication.SignOut();
		}

		public void Reset(UserAuthenticationReset value)
		{
			value.Validate();

			var user = this.UserRepository.GetBy(new UserSpecification
			{
				EmailAddress = value.EmailAddress
			});

			var password = new RandomHelper().Create();
			var salt = new RandomHelper().Create(Settings.Users.PasswordSaltLength);

			user.Password = password.HashToSha1(salt).ToHex();
			user.Salt = salt;

			this.UserRepository.Update(user);

			this.EmailService.Send(new ResetPasswordEmail
			{
				To = user.EmailAddress,
				Name = user.Name,
				EmailAddress = user.EmailAddress,
				Password = password
			});
		}

		public void Update(UserAuthenticationUpdate value)
		{
			value.Validate();

			var user = this.UserRepository.GetBy(new UserSpecification
			{
				EmailAddress = value.EmailAddress
			});

			var salt = new RandomHelper().Create(Settings.Users.PasswordSaltLength);

			user.Password = value.NewPassword.HashToSha1(salt).ToHex();
			user.Salt = salt;

			this.UserRepository.Update(user);

			this.Logout();
		}
	}
}